package org.oep.jmingle;

import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Font;

import org.oep.game.ImageStore;

import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
import java.util.Vector;

/**
 * This is a widget for painting all sorts of neat information about a single minglet or a
 * list of them.
 * @author OEP
 *
 */
public class IDWidget {
	private Vector subjects = new Vector();
	private Image subject;
	private Image basePortrait;
	private MingleTracker tracker;
	
	private Image arrowLeft;
	private Image arrowRight;
	
	private String friendlyLastSeen;
	private int x,y;
	private int width = 125, height = 100;
	private int elementIndex = 0;
	private int source = 0;
	private boolean active = false;
	
	public static final int TRACKER = 0;
	public static final int SUBJECTS = 1;
	
	
	IDWidget(int x, int y, int width, int height, MingleTracker tracker) {
		this.x = x;
		this.y = y;
		this.width = width;
		this.height = height;
		this.tracker = tracker;
		loadImages();
	}
	
	/**
	 * A private alias for loading all the images necessary for this object.
	 */
	private void loadImages() {
		try {
			arrowLeft = ImageStore.getInstance().get("/res/graphics/arrow-left.png");
			arrowRight = ImageStore.getInstance().get("/res/graphics/arrow-right.png");
		}
		catch(IOException e) {
			arrowLeft = null;
			arrowRight = null;
		}
		
		try {
			basePortrait = ImageStore.getInstance().get("/res/graphics/minglet-still.png");
		}
		catch(IOException e) {
			basePortrait = null;
		}
		
	}
	
	/**
	 * Paint the widget if it is active
	 * @param g, the graphics object to paint to
	 */
	public void paint(Graphics g) {
		if(!active) return;
		
		Font f = g.getFont();
		g.setFont(JMingle.DEFAULT_FONT);
		g.setColor(0xFFFFFF);
		g.fillRoundRect(x, y, width, height, width / 10, height / 10);
		g.setColor(0);
		g.drawRoundRect(x, y, width, height, width / 10, height / 10);
		
		
		if(isEmpty()) {
			g.drawString("Your Mingle book is empty!", x + width / 2, y + height / 2, Graphics.BOTTOM | Graphics.HCENTER);
			g.setFont(f);
			return;
		}
		
		if(subject == null) {
			subject = getPortrait();
		}
		
		if(friendlyLastSeen == null || friendlyLastSeen.length() == 0) {
			friendlyLastSeen = getLastSeenTime();
		}
		

		int a = x + width / 2;
		int b = y + height / 4 + subject.getHeight() / 2;
		
		if(subject != null)
			g.drawImage(subject, a, b, Graphics.HCENTER | Graphics.BOTTOM);
		
		int fontHeight = g.getFont().getHeight();
		int startPoint = (y + ((3 * height) / 4) + ((3 * g.getFont().getHeight())) / 2);
		
		// TODO: I think calling getName() and getOwner() so much is a bad idea in a paint() function. Maybe caching would be good.
		g.drawString("Name: " + getName(), x + width / 2, startPoint - 3 * fontHeight, Graphics.BOTTOM | Graphics.HCENTER);
		g.drawString("Owner: " + getOwner(), x + width / 2, startPoint - 2 * fontHeight, Graphics.BOTTOM | Graphics.HCENTER);
		g.drawString("Last seen: " + friendlyLastSeen, x + width / 2, startPoint - fontHeight, Graphics.BOTTOM | Graphics.HCENTER);
		
		// Paint the arrows
		if(hasNext()) {
			if(arrowRight != null) {
				g.drawImage(arrowRight, x + width - 3, y + height / 2, Graphics.RIGHT | Graphics.VCENTER);
			}
			else {
				g.drawString(">>", x + width - 3, y + height / 2, Graphics.RIGHT | Graphics.BASELINE);
			}
		}
			
		if(hasPrevious()) {
			if(arrowLeft != null) {
				g.drawImage(arrowLeft, x + 3, y + height / 2, Graphics.LEFT | Graphics.VCENTER);
			}
			else {
				g.drawString("<<", x + 3, y + height / 2, Graphics.LEFT | Graphics.BASELINE);
			}
		}
		
		g.setFont(f);
	}
	
	/**
	 * Add a new minglet to the vector
	 * @param a, the minglet to add
	 */
	public void addSubject(Minglet a) {
		if(a == null) return;
		
		// TODO: This is slow!
		// We'd like to find a better way to do this some time!
		subjects.addElement( new MingleNode(a.getOwner(), a.getAddress(), a.getLastSeen()) );
	}
	
	/**
	 * Returns the object as it would appear in an initialized state
	 */
	public void clear() {
		subjects.removeAllElements();
		subject = null;
		friendlyLastSeen = null;
		elementIndex = 0;
	}
	
	/**
	 * Go to the next minglet in the data source
	 */
	public void next() {
		if(hasNext()) {
			elementIndex++;
			friendlyLastSeen = null;
			subject = null;
		}
	}
	
	/**
	 * Go to the previous minglet in the data source
	 */
	public void previous() {
		if(hasPrevious()) {
			elementIndex--;
			subject = null;
			friendlyLastSeen = null;
		}
	}
	
	/**
	 * Checks if there is a next minglet to display
	 * @return true if we have another minglet, false if not
	 */
	public boolean hasNext() {
		if(source == IDWidget.TRACKER) {
			return elementIndex < tracker.getCacheSize() - 1;
		}
		else {
			return elementIndex < subjects.size() - 1;
		}
	}
	
	/**
	 * Checks if there is a previous minglet to display.
	 * @return true if we have a previous minglet, false if not
	 */
	public boolean hasPrevious() {
		return elementIndex > 0;
	}
	

	/**
	 * Set the tracker to read from
	 * @param t, the tracker to read from
	 */
	public void setTracker(MingleTracker t) {
		clear();
		tracker = t;
	}
	
	/**
	 * Set the source of the minglet list
	 * @param s - either IDWidget.TRACKER or IDWidget.SUBJECTS
	 */
	public void setSource(int s) {
		source = s;
	}
	
	/**
	 * Set the current status of the widget
	 * @param b - desired state
	 */
	public void setActive(boolean b) {
		active = b;
	}
	
	/**
	 * This method tells whether or not this widget is active
	 * @return true if active, false if not
	 */
	public boolean isActive() {
		return active;
	}
	
	/**
	 * Loads and recolors the minglet base portrait
	 * @return Image object containing the minglet portrait
	 */
	public Image getPortrait() {		
		if(source == IDWidget.SUBJECTS || tracker == null) {
			MingleNode n = (MingleNode) subjects.elementAt(elementIndex);
			return Utils.customizeMinglet(basePortrait, n.getAddress());
		}
		
		MingleNode n = tracker.deviceAt(elementIndex);
		return Utils.customizeMinglet(basePortrait, n.getAddress());
	}
	
	/**
	 * Returns the address of the Bluetooth device
	 * @return Bluetooth device's hardware address
	 * @throws Exception
	 */
	public String getAddress() {
		if(source == IDWidget.SUBJECTS) {
			MingleNode n = (MingleNode) subjects.elementAt(elementIndex);
			return n.getAddress();
		}
		else {// if(source == IDWidget.TRACKER) {
			MingleNode n = tracker.deviceAt(elementIndex);
			return n.getAddress();
		}
	}
	
	/**
	 * Returns the name of the minglet
	 * @return name of minglet
	 */
	public String getName() {
		if(source == IDWidget.SUBJECTS) {
			MingleNode n = (MingleNode) subjects.elementAt(elementIndex);
			return Utils.makeName(n.getAddress());
		}
		
		MingleNode n = tracker.deviceAt(elementIndex);
		return Utils.makeName( n.getAddress() );
	}
	
	/**
	 * Returns the recorded Bluetooth name of the minglet's device
	 * @return name of Bluetooth device
	 */
	public String getOwner() {
		if(source == IDWidget.SUBJECTS) {
			MingleNode n = (MingleNode) subjects.elementAt(elementIndex);
			return n.getName();
		}
		
		MingleNode n = tracker.deviceAt(elementIndex);
		return n.getName();
	}
	
	/**
	 * Returns a human-friendly representation of how long ago the minglet was seen
	 * @return human-friendly time stamp
	 */
	public String getLastSeenTime() {
		long lastSeen;
		if(source == IDWidget.SUBJECTS) {	
			MingleNode n = (MingleNode) subjects.elementAt(elementIndex);
			lastSeen = n.getLastSeen();
		}
		else {
			MingleNode n = tracker.deviceAt(elementIndex);
			lastSeen = n.getLastSeen();
		}

		return Utils.friendlyTimeDiffNow(lastSeen);
	}
	
	/**
	 * Returns whether or not we have anything at all to display.
	 * @return true if empty, false if not
	 */
	public boolean isEmpty() {
		if(source == IDWidget.SUBJECTS) {
			return subjects.size() == 0;
		}
		return tracker.getCacheSize() == 0;
	}

}
